/**
 * This file is part of Megasquirt Logger for PalmOS.
 * Copyright (C) 2011 Andrew Beard
 *
 * Megasquirt Logger is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Megasquirt Logger is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Megasquirt Logger.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "LogFile.h"

#include <PalmOS.h>	

#include <StringMgr.h>
#include <MemoryMgr.h>
#include <StdIOPalm.h>

const Char* LogFile::LOG_FILENAME_EXTENSION = ".frd";

LogFile::LogFile( DateTimeType tDateTime ) : m_nRecordCount( 0 ),
                                             m_LogFile( 0 ),
                                             m_nRealTimeUpdateLength( 0 )
{
    m_pFilename = new Char[ MAX_FILENAME_LENGTH + 1 ];
    CreateFilename( tDateTime,
                    m_pFilename );
    
    m_LastError = VFSFileOpen( FindFirstVolume(),
                               m_pFilename,
                               vfsModeWrite | vfsModeCreate | vfsModeTruncate,
                               &m_LogFile );                  
    if ( m_LastError != errNone )
    {
        // Error opening the file
        m_LogFile = 0;
    } 
}

LogFile::~LogFile()
{
    if ( m_pFilename )
    {
        delete[] m_pFilename;
        m_pFilename = NULL;
    }
    
    if ( m_LogFile )
    {
        VFSFileClose( m_LogFile );
        m_LogFile = 0;
    }
}

bool LogFile::IsFileOpen( void ) const
{
    return ( m_LogFile != 0 );
}

void LogFile::CreateFilename( DateTimeType tDateTime,
                              Char*        pFilenameBuffer ) const
{
    Char bufDateString[ dateStringLength + 1];
    Char bufTimeString[ timeStringLength + 1];
    
    DateToAscii( tDateTime.month,
                 tDateTime.day,
                 tDateTime.year,
                 dfMDYWithDashes,
                 bufDateString );
                 
    TimeToAscii( tDateTime.hour,
                 tDateTime.minute,
                 tfDot24h,
                 bufTimeString );
                 
    StrCopy( pFilenameBuffer,
             "/" );
              
    StrCat( pFilenameBuffer,
            bufDateString );
                 
    StrCat( pFilenameBuffer,
            "_" );
                 
    StrCat( pFilenameBuffer,
            bufTimeString );
            
    StrCat( pFilenameBuffer,
            LOG_FILENAME_EXTENSION );
}

void LogFile::TestWrite( const Char* pString )
{
    UInt32 nBytesWritten    = 0;
    UInt32 nWriteLength     = 0;
    Char   bufErrorCodeString[10];
    
    nWriteLength = StrLen(pString) + 1;
    
    m_LastError = VFSFileWrite( m_LogFile,
                                nWriteLength,
                                pString,
                                &nBytesWritten );
    if ( m_LastError != errNone )
    {
        // Write Error
        
        sprintf( bufErrorCodeString,
                 "%d",
                 m_LastError );
        
        //FrmCustomAlert( VFSErrorAlert, "File write error", bufErrorCodeString, NULL );
        return;
    }
    
    if ( nBytesWritten != nWriteLength )
    {
        // Write Error
        
        sprintf( bufErrorCodeString,
                 "%d",
                 nBytesWritten );
        
        //FrmCustomAlert( VFSErrorAlert, "Write too short", bufErrorCodeString, NULL );
        return;
    }                                 
}

UInt16 LogFile::FindFirstVolume( void ) const 
{
    UInt16 nVolumeNumber  = 0;
    UInt32 nIterator      = vfsIteratorStart;
    Err    tIteratorError;
    
    tIteratorError = VFSVolumeEnumerate( &nVolumeNumber,
                                         &nIterator );
                                         
    if ( tIteratorError == errNone )
    {
        return nVolumeNumber;
    }
    else
    {
        return 0;
    }
}

UInt32 LogFile::GetUnixTime( const DateTimeType* pDateTime ) const
{
    return TimDateTimeToSeconds( pDateTime ) - PALM_TO_UNIX_TIME_OFFSET;
}

void LogFile::WriteHeader( DateTimeType tDateTime,
                           const Char*  pFirmwareSignature,
                           UInt16       nRealTimeUpdateLength )
{
    UInt8  bufHeader[ LOG_HEADER_LENGTH ] = { 0 };
    UInt32 nBytesWritten                  = 0;
    Char   bufErrorCodeString[10];
    
    m_nRealTimeUpdateLength = nRealTimeUpdateLength;
    
	// File Format
    bufHeader[0] = 'F';
    bufHeader[1] = 'R';
    bufHeader[2] = 'D';
    
	// Format Version
	*(UInt16*)(bufHeader + 6) = FRD_FORMAT_VERSION;
	
	// Timestamp
	*(UInt32*)(bufHeader + 8) = GetUnixTime( &tDateTime );
	
	// Firmware Signature
    StrCopy( (Char*)(bufHeader + 12),
             pFirmwareSignature );
			 
	// Data Begin Index
	bufHeader[75] = 0;
	bufHeader[76] = 0;
	bufHeader[77] = 0;
	bufHeader[78] = 81;	

	// Output Length
	bufHeader[79] = (UInt8)((nRealTimeUpdateLength >> 8) & 0xFF);
	bufHeader[80] = (UInt8)(nRealTimeUpdateLength & 0xFF);
    
    m_LastError = VFSFileWrite( m_LogFile,
                                LOG_HEADER_LENGTH,
                                bufHeader,
                                &nBytesWritten );
    
    if ( m_LastError != errNone )
    {
        // Write Error
        
        sprintf( bufErrorCodeString,
                 "%d",
                 m_LastError );
        
        //FrmCustomAlert( VFSErrorAlert, "Header write error", bufErrorCodeString, NULL );
        return;
    }
    
    if ( nBytesWritten != LOG_HEADER_LENGTH )
    {
        // Write Error
        
        sprintf( bufErrorCodeString,
                 "%d",
                 nBytesWritten );
        
        //FrmCustomAlert( VFSErrorAlert, "Header write too short", bufErrorCodeString, NULL );
        return;
    } 
}

void LogFile::WriteOutputRecord( const UInt8* pData )
{
    T_RecordHeaderType tOutputRecordHeader;
    UInt32             nBytesWritten = 0;
    
    tOutputRecordHeader.recordType = OUTPUT_RECORD;
    tOutputRecordHeader.counter    = m_nRecordCount++;
    
    m_LastError = VFSFileWrite( m_LogFile,
                                sizeof(tOutputRecordHeader),
                                &tOutputRecordHeader,
                                &nBytesWritten );
                                
    if ( m_LastError != errNone )
    {
        // Write Error
        return;
    }
    
    if ( nBytesWritten != sizeof(tOutputRecordHeader) )
    {
        // Write too short
        return;
    } 
    
    m_LastError = VFSFileWrite( m_LogFile,
                                m_nRealTimeUpdateLength,
                                pData,
                                &nBytesWritten );
                                
    if ( m_LastError != errNone )
    {
        // Write Error
        return;
    }
    
    if ( nBytesWritten != m_nRealTimeUpdateLength )
    {
        // Write too short
        return;
    } 
}

void LogFile::WriteMarkerRecord( DateTimeType tTimestamp )
{
    T_RecordHeaderType tMarkerRecordHeader;
    UInt32             nBytesWritten  = 0;
    UInt32             nUnixTimestamp = 0;
    Char               bufErrorCodeString[10];
    
    tMarkerRecordHeader.recordType = MARKER_RECORD;
    tMarkerRecordHeader.counter    = m_nRecordCount++;
    
    m_LastError = VFSFileWrite( m_LogFile,
                                sizeof(tMarkerRecordHeader),
                                &tMarkerRecordHeader,
                                &nBytesWritten );
                                
    if ( m_LastError != errNone )
    {
        // Write Error
        
        sprintf( bufErrorCodeString,
                 "%d",
                 m_LastError );
        
        //FrmCustomAlert( VFSErrorAlert, "Header write error", bufErrorCodeString, NULL );
        return;
    }
    
    if ( nBytesWritten != sizeof(tMarkerRecordHeader) )
    {
        // Write Error
        
        sprintf( bufErrorCodeString,
                 "%d",
                 nBytesWritten );
        
        //FrmCustomAlert( VFSErrorAlert, "Header write too short", bufErrorCodeString, NULL );
        return;
    } 
    
    nUnixTimestamp = GetUnixTime( &tTimestamp );
    m_LastError = VFSFileWrite( m_LogFile,
                                sizeof(nUnixTimestamp),
                                &nUnixTimestamp,
                                &nBytesWritten );
                                
    if ( m_LastError != errNone )
    {
        // Write Error
        
        sprintf( bufErrorCodeString,
                 "%d",
                 m_LastError );
        
        //FrmCustomAlert( VFSErrorAlert, "Data write error", bufErrorCodeString, NULL );
        return;
    }
    
    if ( nBytesWritten != sizeof(nUnixTimestamp) )
    {
        // Write Error
        
        sprintf( bufErrorCodeString,
                 "%d",
                 nBytesWritten );
        
        //FrmCustomAlert( VFSErrorAlert, "Data write too short", bufErrorCodeString, NULL );
        return;
    } 
} 

Err LogFile::GetLastError( void ) const
{
    return m_LastError;
}